#include <iostream>
#include <cassert>
#include "fmb.h"

using namespace std;
using namespace fm::base;

const int NUM_THREADS = 200;
const int NUM_ELEMENTS = 50000;

List<int> list;

void fillList(List<int> &list);

void fillList0() {
  fillList(list);
}

void fillList(List<int> &list) {
  for (int i = 0; i < NUM_ELEMENTS; ++i) {
    list.add(i);
    Thread::sleep(1);
  }
}

void testList(List<int> &list) {
  cout << "list.num() = " << list.num() << endl;
  assert(list.num() == NUM_THREADS * NUM_ELEMENTS);

  cout << "Testing elements" << endl;
  int count[NUM_ELEMENTS] = {0};
  for (int i = 0; i < list.num(); ++i) {
    ++count[list[i]];
  }

  for (int i = 0; i < NUM_ELEMENTS; ++i)
    assert(count[i] == NUM_THREADS);

  cout << "Testing elements done" << endl;
}


int main(int argc, char **argv) {
  cout << "List test start" << endl;

  cout << "Filling list: NUM_THREADS = " << NUM_THREADS << "; NUM_ELEMENTS = " << NUM_ELEMENTS << endl;
  {
    char *buf = new char[NUM_THREADS * sizeof(Thread)];
    char *p = buf;
    for (int i = 0; i < NUM_THREADS; ++i, p += sizeof(Thread))
      new (p) Thread(static_cast<Thread::RunFn>(&fillList0));

    Thread *t = (Thread*)buf;
    for (int i = 0; i < NUM_THREADS; ++i, ++t) Thread::join(*t);

    t = (Thread*)buf;
    for (int i = 0; i < NUM_THREADS; ++i, ++t) t->~Thread();

    delete[] buf;
  }
  cout << "Filling list: done" << endl;

  cout << "Testing" << endl;

  testList(list);

  cout << "Testing done" << endl;

  cout << "Testing asigment operator" << endl;
  List<int> list2;
  list2 = list;
  testList(list2);
  cout << "Testing asigment operator done" << endl;

  cout << "Testing copy constructor" << endl;
  List<int> list3(list);
  testList(list3);
  cout << "Testing copy constructor done" << endl;

  cout << "List test done" << endl;
  return 0;
}